#include "task.h"
#include "kernel.h"
#include "mm.h"
#include "assert.h"
#include "string.h"

extern task_t* current;

task_t* tasks[NR_TASKS] = {0};

void* t1(void* arg)
{
    int processor_id = 0;
    
    for (size_t i = 0; i < 500000; i++)
    {
        asm volatile("swapgs;"
            "mov %%gs:0, %0;"
            "swapgs;"
            :"=r"(processor_id)::"rax");
        printk_fixed_position(160 * 20, "processor id: %d, t1:%d", processor_id, i);
    }
}

void* t2(void* arg)
{
    int processor_id = 0;
    
    for (size_t i = 0; i < 500000; i++)
    {
        asm volatile("swapgs;"
            "mov %%gs:0, %0;"
            "swapgs;"
            :"=r"(processor_id)::"rax");
        printk_fixed_position(160 * 21, "processor id: %d, t2:%d", processor_id, i);
    }
}

void* t3(void* arg)
{
    int processor_id = 0;
    
    for (size_t i = 0; i < 500000; i++)
    {
        asm volatile("swapgs;"
            "mov %%gs:0, %0;"
            "swapgs;"
            :"=r"(processor_id)::"rax");
        printk_fixed_position(160 * 22, "processor id: %d, t3:%d", processor_id, i);
    }
}

void* t4(void* arg)
{
    int processor_id = 0;
    
    for (size_t i = 0; i < 500000; i++)
    {
        asm volatile("swapgs;"
            "mov %%gs:0, %0;"
            "swapgs;"
            :"=r"(processor_id)::"rax");
        printk_fixed_position(160 * 23, "processor id: %d, t4:%d", processor_id, i);
    }
}

// void* test_task(void* arg)
// {
//     for (int i = 0; i < 10; i++) {
//         printk("zhuguoyin test task!\n");
//     }
// }

static int find_empty_process()
{
    for (int i = 0; i < NR_TASKS; i++)
    {
        if (tasks[i] == 0)
        {
            return i;
        }
    }
    printk("no empty process\n");
    return -1;
}

task_t* task_create(task_fun_t fun, char* name)
{
    task_t *task = kmalloc(sizeof(task_t));
    task->state = TASK_INIT;
    task->pid = find_empty_process();
    assert(task->pid < NR_TASKS && task->pid >= 0);
    tasks[task->pid] = task;
    task->function = fun;

    task->esp0 = (char*) kmalloc(4096) + PAGE_SIZE;
    strcpy(task->name, name);
    task->state = TASK_READY;
    return task;
}

task_fun_t get_task_function(task_t* task)
{
    assert(NULL != task);
    assert(NULL != task->function);
    return task->function;
}

void task_exit(task_t* task, int exit_code)
{
    assert(NULL != task);
    for (int i = 0; i < NR_TASKS; i++)
    {
        task_t* tmp = tasks[i];
        if (task == tmp)
        {
            printk("task exit: %s\n", tmp->name);
            tmp->exit_code = exit_code;
            tasks[i] = NULL;
            current = NULL;

            kfree_s(task->esp0, PAGE_SIZE);
            kfree_s(task, sizeof(task_t));
            break;
        }
        
    }
    
}

task_context_t* get_task_context(task_t* task)
{
    assert(NULL != task);
    return &task->context;
}

int inc_scheduling_times(task_t* task)
{
    assert(NULL != task);
    return task->scheduling_times++;

}

void task_init()
{
    task_create(t1, "t1");
    task_create(t2, "t2");
    task_create(t3, "t3");
    task_create(t4, "t4");
    // task_create(test_task, "test_task");
}

int64 get_esp0(task_t* task)
{
    return task->esp0;
}

void set_task_ready(task_t* task)
{
    assert(NULL != task);
    task->state = TASK_READY;
}